﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Simpletron
{
  public abstract class Instruction
  {
    public void Execute(ExecutionContext context)
    {
      DoExecute(context);
    }

    protected abstract void DoExecute(ExecutionContext context);

    public override string ToString()
    {
      return this.GetType().Name;
    }
  }

  public sealed class ReadInstruction : Instruction
  {
    internal ReadInstruction() { }
  
    protected override void DoExecute(ExecutionContext context)
    {
      context.RaiseInputRequest();
    }
  }

  public sealed class WriteInstruction : Instruction
  {
    internal WriteInstruction() { }
  
    protected override void DoExecute(ExecutionContext context)
    {
      context.RaiseOutputAwaits();
    }
  }

  public sealed class LoadInstruction : Instruction
  {
    internal LoadInstruction() { }
  
    protected override void DoExecute(ExecutionContext context)
    {
      context.Accumulator = context.Memory[context.Operand];
    }
  }

  public sealed class StoreInstruction : Instruction
  {
    internal StoreInstruction() { }
  
    protected override void DoExecute(ExecutionContext context)
    {
      context.Memory[context.Operand] = context.Accumulator;
    }
  }

  public sealed class AddInstruction : Instruction
  {
    internal AddInstruction() { }
  
    protected override void DoExecute(ExecutionContext context)
    {
      context.Accumulator += context.Memory[context.Operand];
    }
  }

  public sealed class SubtractInstruction : Instruction
  {
    internal SubtractInstruction() { }
  
    protected override void DoExecute(ExecutionContext context)
    {
      context.Accumulator -= context.Memory[context.Operand];
    }
  }

  public sealed class DivideInstruction : Instruction
  {
    internal DivideInstruction() { }

    protected override void DoExecute(ExecutionContext context)
    {
      context.Accumulator /= context.Memory[context.Operand];
    }
  }

  public sealed class MultiplyInstruction : Instruction
  {
    internal MultiplyInstruction() { }
  
    protected override void DoExecute(ExecutionContext context)
    {
      context.Accumulator *= context.Memory[context.Operand];
    }
  }

  public sealed class BranchInstruction : Instruction
  {
    internal BranchInstruction(){ }

    protected override void DoExecute(ExecutionContext context)
    {
      context.Counter = context.Operand;
    }
  }
  
  public sealed class BranchNegInstruction : Instruction
  {
    internal BranchNegInstruction(){ }

    protected override void DoExecute(ExecutionContext context) 
    {
      if (context.Accumulator < 0)
      {
        context.Counter = context.Operand;
      }
    }
  }
  
  public sealed class BranchZeroInstruction : Instruction
  {
    internal BranchZeroInstruction(){ }

    protected override void DoExecute(ExecutionContext context)
    {
      if (context.Accumulator == 0)
      {
        context.Counter = context.Operand;
      }
    }
  }
  
  public sealed class HaltInstruction : Instruction
  {
    internal HaltInstruction(){ }

    protected override void DoExecute(ExecutionContext context)
    {
      context.ExecutionState = ExecutionState.Stopped;
    }
  }


}
